"""
Copyright 2009, Thomas Dejanovic, Jay Shurtz.
 
This is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation; either version 2.1 of
the License, or (at your option) any later version.

This software is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this software; if not, write to the Free
Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
02110-1301 USA, or see the FSF site: http://www.fsf.org.

This class generates verilog HDL from the hatchling data structure.
"""
#---------------------------------------------------------------------

id = "$Id: verilog_bus_factory.py 667 2010-07-01 00:12:17Z jayshurtz $"
# $URL: http://hatch.googlecode.com/svn/tags/taggle_release_2.3/hatch/hatch_targets/verilog/obsolete/verilog_bus_factory.py $
# $Author: jayshurtz $
version = " ".join(id.split()[1:3])

#---------------------------------------------------------------------

try:
    from hatch_node import HatchNode, hatchNodeClassAndName, hatchNodeErrorString
except ImportError, e:
    raise ImportError, str(e) + "\nAdd hatch_node.py to your PYTHONPATH with 'export PYTHONPATH=$PYTHONPATH:hatch/tools/hatch/hatch_nodes'."

#---------------------------------------------------------------------

class VerilogBusFactory(object):
    """
    """

    def __init__(self):
        """
        """

        pass

    def create(self, hatchNode, targetBus=None):
        """ hatchNode is a hatchling data structure.

            targetBus is the target bus type for the generated verlog.
            If supplied it overrides the definition supplied as a
            property of the hatchling.

            address bus width can be overridden later but it must be
            done before any code is generated.  This needs to be fixed
            rather than generated on the fly because the person sewing
            all the verilog together does not want to have to update
            all the verilog every time a register is added to a
            register block.

        """
        
        # figure out the targe bus type.
        if targetBus==None:
            # query the hatchling
            try:
                targetBus = hatchNode.properties['target']
            except KeyError, e:
                # Property does not exist, and we don't have an override.
                raise AssertionError, hatchNodeErrorString(hatchNode, "No target bus specified, cannot generate Verilog.")
 
        bus_width = 32
        address_width = 30
        if 'small' in targetBus:
            addr_width = 8
        elif'medium' in targetBus:
            addr_width = 12
        elif 'large' in targetBus:
            addr_width = 16
        else:
            addr_width = 30 # full address range. 

        bus = None
        if 'apb' in targetBus:
            bus = BusAPB(bus_width, addr_width, hatchNode)
        else:
            raise NotImplementedError, hatchNodeErrorString(hatchNode, "Target bus " + targetBus + " not implemented yet.")
        
        bus.properties['target'] = targetBus # store the target for future reference.
        return bus

#---------------------------------------------------------------------

class BusBase(HatchNode):

    """
    """

    def __init__(self, name, bus_width, addr_width, hatchNode):
        """ hatchNode is a hatchling data structure.
            targetBus is the target bus type for the generated verlog.

            we have nets, input and output ports like a hatch node to
            keep things simple.  There are also registers and wires.
            as the implementation runs to completion nets should end
            up as either a register or a wire and the nets set should
            be empty.  This is a sanity chek that should be asserted.

            TODO - assert the nets set is empty when verilog
            generation is done.

            also have an rtl property into which rtl generated to
            implement the bus will be placed.
        """

        HatchNode.__init__(self, name)

        self.properties['hatchling'] = hatchNode

        self.properties['addr_width'] = addr_width
        self.properties['bus_width']  = bus_width

        try:
            self.properties['prefix'] = hatchNode.properties['prefix']
        except KeyError, e:
            # Property does not exist, set an empty string prefix.
            self.properties['prefix'] = ""

        hatchNode.properties['nets']         = set{}
        hatchNode.properties['input_ports']  = set{}
        hatchNode.properties['output_ports'] = set{}

        hatchNode.properties['registers'] = set{}
        hatchNode.properties['wires']     = set{}

        hatchNode.properties['rtl'] = ""

#---------------------------------------------------------------------

class BusAPB(BusBase):
    """ it's called BusAPB and not APBBus because the camel case name
        looks beter this way :-)
    """

    def __init__(self, bus_width, addr_width, hatchNode):
        """ hatchNode is a hatchling data structure.
            targetBus is the target bus type for the generated verlog.
        """

        BusBase.__init__(self, 'apb_slave', bus_width, addr_width, hatchNode)

        prefix = self.properties['prefix']

        self.properties['clk']        = "%spclk"%(prefix)
        self.properties['clkEn']      = "%spclk_en"%(prefix)
        self.properties['gatedClk']   = "%sgated_pclk"%(prefix)
        self.properties['gatedClkEn'] = "%sgated_pclk_en"%(prefix)

        self.properties['input_ports'][self.properties['clk']] = 1
        self.properties['input_ports'][self.properties['clkEn']] = 1     
        self.properties['input_ports'][self.properties['gatedClk']] = 1
        self.properties['input_ports'][self.properties['gatedClkEn']] = 1

        # change reset to be active high because [ soap box monologue deleted ].
        self.properties['reset']      = "preset"

        self.properties['input_ports']["%spreset_l"%(prefix)] = 1
        self.properties['wires'][self.properties['reset']] = 1
        self.properties['rtl'] += """
  // make an active high reset.
  assign preset  = ~%spreset_l;
"""%(prefix)


#---------------------------------------------------------------------

class BusMicro(BusBase):
    """
    """

    def __init__(self):
        """
        """
        pass

#---------------------------------------------------------------------
